home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / chmod.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  6KB  |  276 lines

  1. /* chmod - change mode        Author: James da Silva */
  2.  
  3.  
  4. /* Author James da Silva (ihnp4!killer!jaime)
  5.  *
  6.  *  a (hopefully) 7th Edition Unix compatible chmod for Minix.
  7.  */
  8.  
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11.  
  12. #define isop(c)         ((c=='+')||(c=='-')||(c=='='))
  13. #define isperm(c)       ((c=='r')||(c=='w')||(c=='x')||(c=='s')||(c=='t')||\
  14.                          (c=='u')||(c=='g')||(c=='o'))
  15.  
  16. /* The bits associated with user, group, other */
  17. #define U_MSK   (0700 | S_ISUID)
  18. #define G_MSK   (0070 | S_ISGID)
  19. #define O_MSK    0007
  20.  
  21. typedef unsigned short bitset;    /* type used for modes */
  22.  
  23. struct stat st;            /* structure returned by stat() */
  24. char *pname, *arg;
  25. bitset newmode, absolute(), symbolic();
  26. int isabsolute;
  27.  
  28. main(argc, argv)
  29. int argc;
  30. char **argv;
  31. {
  32.   int i;
  33.  
  34.   pname = *(argv++);
  35.   if (argc < 3) usage();
  36.   arg = *argv;            /* save pointer to mode arg */
  37.  
  38.   /* Check for octal mode */
  39.   if (isabsolute = ((*arg >= '0') && (*arg <= '7'))) newmode = absolute();
  40.  
  41.   /* Apply the mode to all files listed */
  42.   for (i = 2; i < argc; i++) {
  43.     argv++;
  44.     if (stat(*argv, &st)) {    /* get current file mode */
  45.         printf("%s: cannot find `%s'\n", pname, *argv);
  46.         exit(1);
  47.     }
  48.  
  49.     /* Calculate new mode for this file */
  50.     if (!isabsolute) newmode = symbolic(st.st_mode);
  51.  
  52.     if (chmod(*argv, newmode)) {    /* change the mode */
  53.         printf("%s: cannot chmod `%s'\n", pname, *argv);
  54.         exit(1);
  55.     }
  56.   }
  57.   exit(0);
  58. }
  59.  
  60.  
  61. /* Absolute interprets an octal mode.
  62.  * The file modes will be set to this value.
  63.  */
  64. bitset absolute()
  65. {
  66.   bitset m;
  67.   char *s;
  68.  
  69.   m = 0;
  70.   s = arg;
  71.  
  72.   /* Convert octal string to integer */
  73.   while ((*s >= '0') && (*s <= '7')) m = m * 8 + (*(s++) - '0');
  74.  
  75.   /* If something else is there, choke */
  76.   if (*s) badmode(s);
  77.  
  78.   return m;
  79. }
  80.  
  81.  
  82. /* Symbolic
  83.  *
  84.  * Processes symbolic mode of the form (in EBNF):
  85.  *      <symbolic> ::= <pgroup> { ',' <pgroup> }.
  86.  *      <pgroup> ::= [ <who> ] <op> <permissions> { <op> <permissions> }.
  87.  *
  88.  *      <who> ::= <whoch> { <whoch> }.
  89.  *      <whoch> ::= 'a' | 'u' | 'g' | 'o'.
  90.  *
  91.  *      <op> ::= '+' | '-' | '='.
  92.  *
  93.  *      <permissions> ::= <permch> { <permch> }.
  94.  *      <permch> ::= 'r' | 'w' | 'x' | 's' | 't' | 'u' | 'g' | 'o'.
  95.  *
  96.  * If <who> is omitted, 'a' is assumed, BUT umask()ed bits are uneffected.
  97.  * If <op> is '=', all unspecified permissions are turned off for this <who>.
  98.  * For permissions 'u', 'g', and 'o', the permissions are taken from the
  99.  * specified set.  i.e.  o=g sets the permissions for other the same as for
  100.  * group.
  101.  *
  102.  * Pain in the duff, isn't it?
  103.  */
  104. bitset symbolic(mode)
  105. bitset mode;
  106. {
  107.   int g, o, u, haswho, haspcopy;
  108.   bitset u_mask, emask, partial, other, applyop();
  109.   char *s, c, op;
  110.  
  111.   s = arg;
  112.   u_mask = umask(0);        /* get the umasked bits */
  113.  
  114.   do {                /* pgroup */
  115.     haswho = u = g = o = 0;
  116.  
  117.     while (!isop(*s)) {
  118.         /* We must have a 'who' then */
  119.         haswho = 1;
  120.         switch (*s) {
  121.             case 'a':    u = g = o = 1;    break;
  122.             case 'u':    u = 1;    break;
  123.             case 'g':    g = 1;    break;
  124.             case 'o':    o = 1;    break;
  125.  
  126.             default:    badmode(s);
  127.         }
  128.         s++;
  129.     }
  130.  
  131.     if (!haswho) {
  132.         u = g = o = 1;    /* assume all */
  133.         emask = ~u_mask;/* effective umask */
  134.     } else
  135.         emask = ~0;
  136.  
  137.  
  138.     /* Process each given operator */
  139.     while (isop(*s)) {
  140.         op = *(s++);
  141.         other = partial = haspcopy = 0;
  142.  
  143.         /* Collect the specified permissions */
  144.  
  145.         while (isperm(*s)) {
  146.  
  147.             /* Berkeley only allows one of 'u' 'g' or 'o'
  148.              * as permissions */
  149.  
  150.             if ((*s == 'u') || (*s == 'g') || (*s == 'o'))
  151.                 if (haspcopy)
  152.                     badmode(s);
  153.                 else
  154.                     haspcopy = 1;
  155.  
  156.             switch (*s) {
  157.                 case 'r':
  158.                 partial |= 4;
  159.                 break;
  160.                 case 'w':
  161.                 partial |= 2;
  162.                 break;
  163.                 case 'x':
  164.                 partial |= 1;
  165.                 break;
  166.  
  167.                 case 'u':
  168.                 partial |= (mode & U_MSK & ~S_ISUID) >> 6;
  169.                 other |= mode & S_ISUID;
  170.                 break;
  171.                 case 'g':
  172.                 partial |= (mode & G_MSK & ~S_ISGID) >> 3;
  173.                 other |= mode & S_ISGID;
  174.                 break;
  175.                 case 'o':
  176.                 partial |= (mode & O_MSK);
  177.                 break;
  178.  
  179. #ifdef S_ISVTX
  180.                 case 't':
  181.                 other |= S_ISVTX;
  182.                 break;
  183. #endif
  184.  
  185.                 case 's':
  186.                 if (u) other |= S_ISUID;
  187.                 if (g) other |= S_ISGID;
  188.                 break;
  189.  
  190.                 default:    badmode(s);
  191.             }
  192.             s++;
  193.         }
  194.  
  195.         /* Apply the op using the affected bits and masks */
  196.         if (u)
  197.             mode = applyop(mode, op, (other | (partial << 6)), emask, U_MSK);
  198.         if (g)
  199.             mode = applyop(mode, op, (other | (partial << 3)), emask, G_MSK);
  200.         if (o)
  201.             mode = applyop(mode, op, (other | partial), emask, O_MSK);
  202.     }
  203.  
  204.   } while (*(s++) == ',');
  205.  
  206.   /* Not at end - choke */
  207.  
  208.   if (*(--s)) badmode(s);
  209.  
  210.   return mode;
  211. }
  212.  
  213.  
  214. /* Applyop
  215.  *
  216.  * applies the operator to the current mode using the specified bitset
  217.  * and mask.  'bits' will contain 1's in every bit affected by the
  218.  * operator '+', '-', or '='.  In the case of '=', msk is used to
  219.  * determine which bits will be forced off. 'emask' is the effective
  220.  * umask.
  221.  */
  222. bitset applyop(mode, op, bits, emask, msk)
  223. char op;
  224. bitset mode, bits, emask, msk;
  225. {
  226.   switch (op) {
  227.       case '+':
  228.     mode |= bits & emask;    /* turn these bits on */
  229.     break;
  230.       case '-':
  231.     mode &= ~(bits & emask);/* turn these off */
  232.     break;
  233.       case '=':
  234.     mode |= bits & emask;    /* turn these bits on */
  235.     mode &= ~(~bits & msk & emask);    /* others off */
  236.     break;
  237.       default:            /* should never get here (famous last words) */
  238.     printf("%s: panic: bad op `%c' passed\n", pname, op);
  239.   }
  240.   return mode;
  241. }
  242.  
  243.  
  244. /* Usage
  245.  *
  246.  * Prints a terse usage message and exits.
  247.  */
  248. usage()
  249. {
  250.   printf("Usage: %s [absolute-mode | symbolic-mode] files\n", pname);
  251.   exit(1);
  252. }
  253.  
  254.  
  255. /* Badmode
  256.  *
  257.  * Called when the parser chokes on the given mode.
  258.  * Prints a message showing the offending character and exits.
  259.  */
  260. badmode(s)
  261. char *s;
  262. {
  263.   int i, sp;
  264.   char buffer[80], *bp;
  265.  
  266.   sp = s - arg + strlen(pname) + 21;
  267.   sp = sp > 79 ? 79 : sp;    /* check for buffer overflow */
  268.  
  269.   for (i = 0, bp = buffer; i < sp; i++, bp++) *bp = ' ';
  270.   *bp = '\0';
  271.  
  272.   printf("%s: badly formed mode `%s'\n", pname, arg);
  273.   printf("%s^\n", buffer);
  274.   exit(1);
  275. }
  276.